package crmdna.practice;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyFilter;

import crmdna.client.Client;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.practice.Practice.PracticeProp;
import crmdna.user.User;
import crmdna.user.User.Action;
import crmdna.user.User.ResourceType;

public class PracticeTest {
	
	private final LocalServiceTestHelper datastoreHelper =
		        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
		        .setApplyAllHighRepJobPolicy());
	
	private final String client = "isha";
 	private final String invalidClient = "invalid";
 	private final String validUser = "valid@login.com";
 	private final String userWithPermission = "withpermission@login.com";
	
    @Before
    public void setUp() {
        datastoreHelper.setUp();  
        ObjectifyFilter.complete();
        
        Client.create(client);
        
        //can call getAll without any groups
    	List<PracticeProp> props = Practice.getAll(client);
    	assertEquals(0, props.size());
    	
        long groupId = crmdna.group.Group.create(client, "Singapore", User.SUPER_USER).groupId;
        assertEquals(1, groupId);
       
        User.create(client, validUser, groupId, User.SUPER_USER);
        assertEquals(1, User.get(client, validUser).toProp().userId);
        
        User.create(client, userWithPermission, groupId, User.SUPER_USER);
        assertEquals(2, User.get(client, userWithPermission).toProp().userId);
        
        User.addOrDeletePrivilege(client, userWithPermission, ResourceType.PRACTICE, 0, 
        		Action.WRITE, true, User.SUPER_USER);             
    }

    @After
    public void tearDown() {       
    	ObjectifyFilter.complete();
        datastoreHelper.tearDown();
    }
    
    @Test
    public void createTest() {    	
    	
    	PracticeProp prop = Practice.create(client, "Isha Kriya", userWithPermission);
    	assertEquals("first entity has id 1", 1, prop.practiceId);
    	
    	prop = Practice.safeGet(client, prop.practiceId).toProp();
    	assertEquals("name is populated correctly", "isha kriya", prop.name);
    	assertEquals("display name is populated correctly", 
    			"Isha Kriya", prop.displayName);
    	
    	//cannot create duplicate
    	try {
    		Practice.create("isha", "ISHA KRIYA", User.SUPER_USER);
    		assertTrue(false);
    	} catch (APIException e) {
    		assertEquals("cannot create duplicate practice", 
    				Status.ERROR_RESOURCE_ALREADY_EXISTS, e.statusCode);
    	}
    	
    	//ids should be in sequence
    	prop = Practice.create(client, "Shoonya", userWithPermission);
    	assertEquals("practice id is in sequence", 2, prop.practiceId);
    	prop = Practice.create(client, "Shambhavi", userWithPermission);
    	assertEquals("practice id is in sequence", 3, prop.practiceId);
    	prop = Practice.create(client, "Surya Kriya", userWithPermission);
    	assertEquals("practice id is in sequence", 4, prop.practiceId);
    	
    	prop = Practice.safeGet(client, 2).toProp();
    	assertEquals("name is populated correctly", "shoonya", prop.name);
    	assertEquals("display name is populated correctly", "Shoonya", prop.displayName);
    	prop = Practice.safeGet(client, 3).toProp();
    	assertEquals("display name is populated correctly", 
    			"Shambhavi", prop.displayName);
    	prop = Practice.safeGet(client, 4).toProp();
    	assertEquals("display name is populated correctly", "Surya Kriya", prop.displayName);
    	assertEquals("name is populated correctly", "surya kriya", prop.name);
    	
    	//access control
    	try {
    		Practice.create("isha", "Hata Yoga", validUser);
    		assertTrue(false);
    	} catch (APIException e) {
    		assertEquals("permission required to edit practice", 
    				Status.ERROR_INSUFFICIENT_PERMISSION, e.statusCode);
    	}
    	
    	//client should be valid
    	try {
    		Practice.create(invalidClient, "Aum Chanting", User.SUPER_USER);
    		assertTrue(false);
    	} catch (APIException e) {
    		assertEquals("client should be valid", Status.ERROR_RESOURCE_NOT_FOUND, e.statusCode);
    	}    	
    }
    
    @Test
    public void safeGetTest() {   
    	
    	PracticeProp prop = Practice.create(client, "Shoonya", userWithPermission);
    	assertTrue(prop.practiceId != 0);
    	
    	prop = Practice.safeGet("isha", prop.practiceId).toProp();
    	assertEquals("name is populated correctly", "shoonya", prop.name);
    	assertEquals("display name is populated correctly", "Shoonya", prop.displayName);
    	
    	//exception for non existing
    	try {
    		Practice.safeGet("isha", prop.practiceId + 20939); //non existant
    		assertTrue(false);
    	} catch (APIException ex) {
    		assertEquals("exception thrown for non exisitng practise id", 
    				Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    	}
    }
    
    @Test
    public void renameTest() {    	
    	PracticeProp shoonya = Practice.create("isha", "Shoonya", userWithPermission);
    	Practice.create(client, "Shambhavi", userWithPermission);
    	
    	try {
    		Practice.rename("isha", shoonya.practiceId, "Shambhavi", userWithPermission);
    		assertTrue(false);
    	} catch (APIException ex) {
    		assertEquals("cannot rename to existing", 
    				Status.ERROR_RESOURCE_ALREADY_EXISTS, ex.statusCode);
    	}
    	
    	//can change case and rename
    	Practice.rename("isha", shoonya.practiceId, "shoonya", userWithPermission);
    	shoonya = Practice.safeGet("isha", shoonya.practiceId).toProp();
    	assertEquals("name correctly populated after rename", "shoonya", shoonya.name);
    	assertEquals("name correctly populated after rename", "shoonya", shoonya.displayName);
    	
    	Practice.rename("isha", shoonya.practiceId, "Shoonya Meditation", userWithPermission);
    	shoonya = Practice.safeGet("isha", shoonya.practiceId).toProp();
    	assertEquals("name populated correctly", "shoonya meditation", shoonya.name);
    	assertEquals("display name populated correctly", "Shoonya Meditation", shoonya.displayName);    
    	
    	try {
    		Practice.rename("isha", shoonya.practiceId, "Shoonya", validUser);
    		assertTrue(false);
    	} catch (APIException ex) {
    		assertEquals("permission required to rename practice", 
    				Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    	}    
    	
    	try {
    		Practice.rename(invalidClient, shoonya.practiceId, "Shoonya", userWithPermission);
    		assertTrue(false);
    	} catch (APIException ex) {
    		assertEquals("client should be valid", Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    	}      	
    }
    
    @Test
    public void getAllTest() {    	    	    
    	Practice.create("isha", "Shoonya", userWithPermission);
    	Practice.create("isha", "Shambhavi", userWithPermission);    	
    	ObjectifyFilter.complete();
    	
    	List<PracticeProp> props = Practice.getAll("isha");
    	assertEquals(2, props.size());
    	//should be sorted
    	assertEquals("shambhavi", props.get(0).name);
    	assertEquals("Shambhavi", props.get(0).displayName);
    	assertEquals("shoonya", props.get(1).name);
    	assertEquals("Shoonya", props.get(1).displayName);    	    	    	
    }            
    
    @Test
    public void toPropTest() {
    	PracticeEntity entity = new PracticeEntity();
    	entity.practiceId = 123l;
    	entity.displayName = "Shoonya";
    	entity.name = entity.displayName.toLowerCase();
    	
    	PracticeProp prop = entity.toProp();
    	assertEquals("practise id correctly populated", 123, prop.practiceId);
    	assertEquals("display name correctly populated", "Shoonya", prop.displayName);
    	assertEquals("name correctly populated", "shoonya", prop.name);    	    	
    }
    
    @Test public void getPracticeIdsTest() {
    	assertTrue(false);
    }
}
